﻿using System.IO;
using System.Xml.Linq;
using System.Xml.Schema;
using Framework.Core;
using Xunit;

namespace Framework.Tests.Core
{
    public class LinqToXmlPatchExtensionTest
    {
        [Fact]
        public void Same_xmls_are_equals()
        {
            var autoClosedXml = XDocument.Parse(@"<root/>");

            Assert.True(autoClosedXml.DeepEqualsWithNormalization(autoClosedXml));
        }

        [Fact]
        public void Auto_closed_node_are_equals()
        {
            var autoClosedXml = XDocument.Parse(@"<root/>");
            var simpleXml = XDocument.Parse(@"<root></root>");

            Assert.True(autoClosedXml.DeepEqualsWithNormalization(simpleXml));
        }

        [Fact]
        public void Should_exclude_comment()
        {
            var autoClosedXml = XDocument.Parse(@"<!--Hello--><root/>");
            var simpleXml = XDocument.Parse(@"<root></root>");

            Assert.True(autoClosedXml.DeepEqualsWithNormalization(simpleXml));
        }

        [Fact]
        public void Should_test_xsd()
        {
            const string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
<xs:schema id=""root"" xmlns="""" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
  <xs:element name=""root"" msdata:IsDataSet=""true"" msdata:Locale=""en-US"">
    <xs:complexType>
      <xs:choice minOccurs=""0"" maxOccurs=""unbounded"">
        <xs:element name=""String"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:string"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""DateTime"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:dateTime"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""Boolean"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:boolean"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""Decimal"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:decimal"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""Double"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:double"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""Float"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:float"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""HexBinary"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:hexBinary"" />
          </xs:complexType>
        </xs:element>
        <xs:element name=""Language"">
          <xs:complexType>
            <xs:attribute name=""value"" type=""xs:language"" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

";

            var xml = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<root>
  <String value=""value1"" />
  <DateTime value=""1900-01-01T01:01:01+01:00"" />
  <Boolean value=""true"" />
  <Decimal value=""1"" />
  <Double value=""1"" />
  <Float value=""1"" />
  <HexBinary value=""0FB7"" />
  <Language value=""en"" />
</root>
    ");

            TestNormalization(xsd, xml);
        }

        [Fact]
        public void Should_test_xsd_on_element()
        {
            const string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
<xs:schema id=""NewDataSet"" xmlns="""" xmlns:xs=""http://www.w3.org/2001/XMLSchema"" xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
  <xs:element name=""root"">
    <xs:complexType>
      <xs:sequence>
        <xs:element name=""string"" type=""xs:string"" minOccurs=""1"" />
        <xs:element name=""boolean"" type=""xs:boolean"" minOccurs=""1"" />
        <xs:element name=""dateTime"" type=""xs:dateTime"" minOccurs=""1"" />
        <xs:element name=""decimal"" type=""xs:decimal"" minOccurs=""1"" />
        <xs:element name=""double"" type=""xs:double"" minOccurs=""1"" />
        <xs:element name=""float"" type=""xs:float"" minOccurs=""1"" />
        <xs:element name=""hexBinary"" type=""xs:hexBinary"" minOccurs=""1"" />
        <xs:element name=""language"" type=""xs:language"" minOccurs=""1"" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

";

            var xml = XDocument.Parse(@"<?xml version=""1.0"" encoding=""utf-8""?>
<root>
  <string>string1</string>
  <boolean>true</boolean>
  <dateTime>1900-01-01T01:01:01+01:00</dateTime>
  <decimal>1</decimal>
  <double>1</double>
  <float>1</float>
  <hexBinary>0FB7</hexBinary>
  <language>en</language>
</root>");

            TestNormalization(xsd, xml);
        }

        private static void TestNormalization(string xsd, XDocument xml)
        {
            var schema = new XmlSchemaSet();

            using (var stream = new MemoryStream())
            {
                var writer = new StreamWriter(stream);

                writer.Write(xsd);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                schema.Add(XmlSchema.Read(stream, null));
            }

            xml.Validate(schema, null);

            xml.Normalize(schema);

            Assert.True(XNode.DeepEquals(xml, xml));
        }
    }
}